import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.BorderFactory;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.JButton;

import aima.search.framework.Problem;
import aima.search.framework.Search;
import aima.search.framework.SearchAgent;
import aima.search.informed.HillClimbingSearch;
import aima.search.informed.SimulatedAnnealingSearch;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.Canvas;
import java.awt.FlowLayout;

@SuppressWarnings({"unused", "rawtypes", "unchecked"})
public class IAPrac1Jframe extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JPanel contentPane;
	private JTextField textField;
	private JTextField textField_1;
	private JScrollPane scrollPane;
	private JTextArea textArea;
	private IAPrac1CityMap drawPanel;
	
	private JRadioButton rdbtnHillClimbing;
	private JRadioButton rdbtnSimulatedAnnealing;
	private JRadioButton rdbtnCriterioA;
	private JRadioButton rdbtnCriterioB;
	private JRadioButton rdbtnGeneracinA;
	private JRadioButton rdbtnGeneracinB;
	
	private static int HILL_CLIMBING = 1;
	private static int SIMULATED_ANNEALING = 2;
	private static int HEURISTIC_A = 1;
	private static int HEURISTIC_B = 2;
	private static int INIT_A1 = 1;
	private static int INIT_B1 = 2;
	
	private int N;
	private int M;
	private int heur;
	private int alg;
	private int stateIni;
	private IAPrac1State state;
	private IAPrac1State copyState;
	private static int nsteps = 100000;
	private static int niter = 100;
	private static int k = 25;
	private static double lambda = 0.1;
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					IAPrac1Jframe frame = new IAPrac1Jframe();
					frame.setTitle("[IA] Practica 1: Busqueda local");
					frame.setSize(new Dimension(1050, 900));
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public IAPrac1Jframe() {
		N = 20;
		M = 10;
		heur = 1;
		alg = 1;
		stateIni = 1;
		
		drawPanel = new IAPrac1CityMap();
		FlowLayout flowLayout = (FlowLayout) drawPanel.getLayout();
		flowLayout.setVgap(10);
		flowLayout.setHgap(10);
		state = new IAPrac1State(N, M);
		drawPanel.setCityMap(IAPrac1State.N, IAPrac1State.NUM_COORD, IAPrac1State.registro, IAPrac1State.K);
		drawPanel.setPreferredSize(new Dimension(660, 660));
		//drawPanel.setBorder(BorderFactory.createLineBorder(Color.black));
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 847, 661);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		
		JLabel lblNmeroUsuarios = new JLabel("Numero usuarios:");
		
		textField = new JTextField();
		textField.setColumns(10);
		textField.setText(String.valueOf(N));
		
		JLabel lblNmeroNoConductores = new JLabel("Numero no conductores:");
		
		textField_1 = new JTextField();
		textField_1.setColumns(10);
		textField_1.setText(String.valueOf(M));
		
		JLabel lblAlgoritmos = new JLabel("Algoritmos:");
		
		rdbtnHillClimbing = new JRadioButton("Hill Climbing");
		rdbtnHillClimbing.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {
				alg = HILL_CLIMBING;
				rdbtnHillClimbing.setSelected(true);
				rdbtnSimulatedAnnealing.setSelected(false);
			}
		});
		rdbtnHillClimbing.setSelected(true);
		
		rdbtnSimulatedAnnealing = new JRadioButton("Simulated Annealing");
		rdbtnSimulatedAnnealing.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				alg = SIMULATED_ANNEALING;
				rdbtnHillClimbing.setSelected(false);
				rdbtnSimulatedAnnealing.setSelected(true);
			}
		});
		
		JLabel lblHeursticos = new JLabel("Heuristicos:");
		
		rdbtnCriterioA = new JRadioButton("Criterio A");
		rdbtnCriterioA.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {
				heur = HEURISTIC_A;
				rdbtnCriterioA.setSelected(true);
				rdbtnCriterioB.setSelected(false);
			}
		});
		rdbtnCriterioA.setSelected(true);
		
		rdbtnCriterioB = new JRadioButton("Criterio B");
		rdbtnCriterioB.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {
				heur = HEURISTIC_B;
				rdbtnCriterioA.setSelected(false);
				rdbtnCriterioB.setSelected(true);
			}
		});
		
		JLabel lblEstadoInicial = new JLabel("Estado inicial:");
		
		rdbtnGeneracinA = new JRadioButton("Generacion A1");
		rdbtnGeneracinA.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {
				stateIni = INIT_A1;
				rdbtnGeneracinA.setSelected(true);
				rdbtnGeneracinB.setSelected(false);
			}
		});
		rdbtnGeneracinA.setSelected(true);
		
		rdbtnGeneracinB = new JRadioButton("Generacion B1");
		rdbtnGeneracinB.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {
				stateIni = INIT_B1;
				rdbtnGeneracinA.setSelected(false);
				rdbtnGeneracinB.setSelected(true);
			}
		});
		
		textArea = new JTextArea();
		scrollPane = new JScrollPane(textArea);
		scrollPane.setPreferredSize(new Dimension(300, 660));
		
		JButton btnEjecutar = new JButton("Ejecutar");
		btnEjecutar.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {
				Problem problem = null;
				Search search = null;
				SearchAgent sagent = null;
				
				try {
					N = Integer.parseInt(textField.getText());
					M = Integer.parseInt(textField_1.getText());
					state = new IAPrac1State(N, M);
					drawPanel.setCityMap(IAPrac1State.N, IAPrac1State.NUM_COORD, IAPrac1State.registro, IAPrac1State.K);
					
					if (stateIni == INIT_A1) {
						state.IAPracStateSolucionInicialA1();
					}
					else if (stateIni == INIT_B1) {
						state.IAPracStateSolucionInicialB1();
					}
					
					if (alg == HILL_CLIMBING) {
						search = new HillClimbingSearch();
						if (heur == HEURISTIC_A) {
							problem = new Problem(state, new IAPrac1SuccessorFunction(), new IAPrac1GoalTest(), new IAPrac1HeuristicFunctionA());
						}
						else if (heur == HEURISTIC_B) {
							problem = new Problem(state, new IAPrac1SuccessorFunction(), new IAPrac1GoalTest(), new IAPrac1HeuristicFunctionB());
						}
					}
					else if (alg == SIMULATED_ANNEALING) {
						search = new SimulatedAnnealingSearch(nsteps, niter, k, lambda);
						if (heur == HEURISTIC_A) {
							problem = new Problem(state, new IAPrac1SuccessorFunctionSA(), new IAPrac1GoalTest(), new IAPrac1HeuristicFunctionA());
						}
						else if (heur == HEURISTIC_B) {
							problem = new Problem(state, new IAPrac1SuccessorFunctionSA(), new IAPrac1GoalTest(), new IAPrac1HeuristicFunctionB());
						}
						
					}
					
					sagent = new SearchAgent(problem, search);
					
					// Lista movimientos
					List<String> actions = (List<String>)sagent.getActions();
					
					if (actions.size() == 0) textArea.setText("No actions");
					else {
						// Lista movimientos
						textArea.setText("Movimientos");
						for (int i = 0; i < actions.size(); i++) {
							textArea.append("\n" + actions.get(i));
						}
						
						 for (int i = 0; i < actions.size(); i++) {
					        	String[] params = actions.get(i).split("-");
					        	if (params[0].compareTo(IAPrac1State.ELIMINAR_CONDUCTOR) == 0) {
					        		// Formato: ELIMINAR_CONDUCTOR-con
					        		state.eliminarConductor(Integer.parseInt(params[1]));
					        	}
					        	else if (params[0].compareTo(IAPrac1State.ASIGNAR) == 0) {
					        		// Formato: ASIGNAR-pas-con
					        		state.asignarPasajero(Integer.parseInt(params[1]), Integer.parseInt(params[2]));
					        	}
					        	else if (params[0].compareTo(IAPrac1State.ELIMINAR_PASAJERO) == 0) {
					        		// Formato: ELIMINAR_PASAJERO-con-pas
					        		state.eliminarPasajero(Integer.parseInt(params[1]), Integer.parseInt(params[2]));
					        	}
					        	else if (params[0].compareTo(IAPrac1State.MOVER) == 0) {
					        		// Formato: MOVER-con1-pas-con2
					        		state.moverPasajero(Integer.parseInt(params[1]), Integer.parseInt(params[2]), Integer.parseInt(params[3]));
					        	}
					        	else if (params[0].compareTo(IAPrac1State.INTERCAMBIAR_CONTIGUOS) == 0) {
					        		// Formato: INTERCAMBIAR_CONTIGUOS-con-pos
					        		state.switchPasajeros(Integer.parseInt(params[1]), Integer.parseInt(params[2]));
					        	}
					        	else if (params[0].compareTo(IAPrac1State.INTERCAMBIAR) == 0) {
					        		// Formato: INTERCAMBIAR-con-pos1-pos2
					        		state.switchPosicionesPasajeros(Integer.parseInt(params[1]), Integer.parseInt(params[2]), Integer.parseInt(params[3]));
					        	}
					        	else {
					        		textArea.append("Codigo de operador no definido.");
					        	}
					    }
						
						// Rutas conductores
						textArea.append("\n\nNumero conductores\n"+state.ncond);
						
						textArea.append("\n\nRutas conductores");
						Vector<Vector<Integer>> conds = state.getConductores();
						for (int i = 0; i < conds.size(); i++) { 
						  if (conds.get(i) != null) {
							  textArea.append("\n" + i + conds.get(i).toString());
						  }
						}
						
						textArea.append("\n\nDistancia total(hms)\n"+state.getTotalHmsrec());
						
						// Lista propiedades
						String key = null;
				        String property = null;
				        Properties properties = sagent.getInstrumentation();
						Iterator keys = properties.keySet().iterator();
						
						textArea.append("\n\nPropiedades");
						while (keys.hasNext()) {
				            key = (String) keys.next();
				            property = properties.getProperty(key);
				            textArea.append("\n" + key + " : " + property);
				        }
					}
				} 
		        catch (Exception e) {
		            textArea.setText("Execution error. Check parameters values.");
		        }
			}
		});
		
		JLabel lblMovimientos = new JLabel("Solucion");
		GroupLayout gl_contentPane = new GroupLayout(contentPane);
		gl_contentPane.setHorizontalGroup(
			gl_contentPane.createParallelGroup(Alignment.TRAILING)
				.addGroup(gl_contentPane.createSequentialGroup()
					.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
						.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING, false)
							.addGroup(gl_contentPane.createSequentialGroup()
								.addComponent(lblNmeroUsuarios)
								.addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
								.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
							.addGroup(gl_contentPane.createSequentialGroup()
								.addComponent(lblNmeroNoConductores, GroupLayout.PREFERRED_SIZE, 180, GroupLayout.PREFERRED_SIZE)
								.addPreferredGap(ComponentPlacement.UNRELATED)
								.addComponent(textField_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
						.addGroup(gl_contentPane.createSequentialGroup()
							.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
								.addComponent(lblAlgoritmos)
								.addComponent(lblHeursticos))
							.addPreferredGap(ComponentPlacement.RELATED)
							.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
								.addGroup(gl_contentPane.createSequentialGroup()
									.addComponent(rdbtnCriterioA)
									.addPreferredGap(ComponentPlacement.RELATED)
									.addComponent(rdbtnCriterioB))
								.addGroup(gl_contentPane.createSequentialGroup()
									.addComponent(rdbtnHillClimbing)
									.addPreferredGap(ComponentPlacement.RELATED)
									.addComponent(rdbtnSimulatedAnnealing))))
						.addGroup(gl_contentPane.createSequentialGroup()
							.addComponent(lblEstadoInicial)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(rdbtnGeneracinA)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
								.addComponent(btnEjecutar)
								.addComponent(rdbtnGeneracinB))))
					.addContainerGap(457, Short.MAX_VALUE))
				.addGroup(Alignment.LEADING, gl_contentPane.createSequentialGroup()
					.addContainerGap()
					.addComponent(drawPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
					.addGap(18)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
						.addGroup(gl_contentPane.createSequentialGroup()
							.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
							.addGap(19))
						.addGroup(gl_contentPane.createSequentialGroup()
							.addComponent(lblMovimientos)
							.addContainerGap())))
				.addGroup(Alignment.LEADING, gl_contentPane.createSequentialGroup()
					.addGap(55)
					.addGap(638))
		);
		gl_contentPane.setVerticalGroup(
			gl_contentPane.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_contentPane.createSequentialGroup()
					.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblNmeroUsuarios)
						.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
					.addGap(10)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblNmeroNoConductores)
						.addComponent(textField_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblAlgoritmos)
						.addComponent(rdbtnHillClimbing)
						.addComponent(rdbtnSimulatedAnnealing))
					.addPreferredGap(ComponentPlacement.UNRELATED)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
						.addComponent(lblHeursticos)
						.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
							.addComponent(rdbtnCriterioA)
							.addComponent(rdbtnCriterioB)))
					.addPreferredGap(ComponentPlacement.UNRELATED)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
						.addComponent(lblEstadoInicial)
						.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
							.addComponent(rdbtnGeneracinA)
							.addComponent(rdbtnGeneracinB)))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
						.addComponent(btnEjecutar))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
						.addGroup(gl_contentPane.createSequentialGroup()
							.addGap(6)
							.addComponent(lblMovimientos)
							.addPreferredGap(ComponentPlacement.UNRELATED)
							.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 600, GroupLayout.PREFERRED_SIZE))
						.addComponent(drawPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)))
		);
		contentPane.setLayout(gl_contentPane);
	}
}
